package com.redstar.interesting.common.starter.filter;

import com.redstar.interesting.common.constants.Constants;
import com.redstar.interesting.common.starter.util.IllegalStrFilterUtil;
import jodd.io.StreamUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;

/**
 * post 请求包装对象，同时校验参数的合法性
 *
 * @author lihongxing
 */
public class BodyRequestWrapper extends HttpServletRequestWrapper {
    private static final Logger log = LoggerFactory.getLogger(BodyRequestWrapper.class);

    private static final String GET = "GET";

    private static final String POST = "POST";

    private String method;

    private byte[] postMethodParameter;

    private Map<String, String[]> getMethodParameter;

    /**
     * 取出请求中的参数
     * @param request
     */
    public BodyRequestWrapper(HttpServletRequest request) {
        super(request);
        try {
            method = request.getMethod();
            switch (method) {
                case GET:
                    getMethodParameter = request.getParameterMap();
                    break;
                case POST:
                    postMethodParameter = StreamUtil.readBytes(request.getReader(), "utf-8");
                    break;
                default:
            }
        } catch (IOException e) {
            log.info("读取参数出错");
        }
    }

    /**
     * @return true 表示参数合法
     */
    public boolean isPass() {
        switch (method) {
            case GET:
                return checkGetMethodParameter();
            case POST:
                return checkPostMethodParameter();
            default:
                //默认放行
                return true;
        }

    }

    /**
     * post请求参数不能为null
     * @return
     */
    private boolean checkPostMethodParameter() {
        String data = new String(postMethodParameter);
        if (!StringUtils.hasText(data)) {
            log.info("post请求参数不能为null");
            return false;
        }
        return IllegalStrFilterUtil.sqlStrFilter(data) && !IllegalStrFilterUtil.isIllegalStr(data);
    }

    /**
     * 校验get请求的参数，get请求参数可以为null
     *
     * @return false 说明参数不符合要求
     */
    private boolean checkGetMethodParameter() {
        boolean pass = true;
        if (CollectionUtils.isEmpty(getMethodParameter)) {
            return pass;
        }
        Collection<String[]> values = getMethodParameter.values();
        for (String[] value : values) {

            String s = Arrays.toString(value);
            String substring = s.substring(Constants.ONE, s.length() - Constants.ONE);
            if (!IllegalStrFilterUtil.sqlStrFilter(substring)) {
                log.info("参数:\"{}\"有SQL注入的风险,请求被拦截", substring);
                pass = false;
                break;
            }
            if (IllegalStrFilterUtil.isIllegalStr(substring)) {
                log.info("参数:\"{}\"有特殊字符,请求被拦截", substring);
                pass = false;
                break;
            }
        }
        return pass;
    }


    /*
     * getReader 和 getInputStream 不可同时使用，本类进行了getReader,为了保证controller层获取参数时不报错，所以重写这两个方法
     */

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() {
        final ByteArrayInputStream bais = new ByteArrayInputStream(postMethodParameter);
        return new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener listener) {}

            @Override
            public int read() throws IOException {
                return bais.read();
            }
        };

    }


}
